<?php
/**************************************************************************
 *
 *   Copyright 2010 American Public Media Group
 *
 *   This file is part of AIR2.
 *
 *   AIR2 is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   AIR2 is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with AIR2.  If not, see <http://www.gnu.org/licenses/>.
 *
 *************************************************************************/

require_once 'AIR2_CRUD_Controller.php';

/**
 * User Controller
 *
 * @package default
 */
class User_Controller extends AIR2_CRUD_Controller {

    public $base_model_name = 'User';
    public $base_view_name  = 'user';
    public $exposed_relations = array(
        'email' => 'UserEmailAddress',
        'phone' => 'UserPhoneNumber',
        'uri' => 'UserUri',
        'organizations' => 'UserOrg',
        'photo' => 'UserUri',
        'activity' => true, // NO AIR2_Query!
        'networks' => 'UserUri',
    );
    public $flatten_mapping = array(
        //'UserOrg'   => 'Organization',
    );
    public $image_proxies = array('photo');
    public $column_whitelist = array('uo_ar_id');
    public $unique_name_col = 'user_username';
    public $valid_args = array(
        'type' => 'query_user_type',
        'excl_org' => 'query_excl_org',
    );


    /**
     * Add custom relations to queries to this controller
     *
     * @param AIR2_Query $q
     * @param boolean $deeply (optional)
     */
    protected function _add_query_load_related(&$q, $deeply=true) {
        if (!$this->rel_uri) { // base User level
            $q->leftJoin('a.UserOrg uo WITH uo.uo_home_flag = true');
            $q->leftJoin('uo.Organization o');
            $q->leftJoin('a.UserEmailAddress e with e.uem_primary_flag = true');
            $q->leftJoin('a.UserPhoneNumber p with p.uph_primary_flag = true');
            $q->leftJoin('a.CreUser c');
        }
        elseif ($this->rel_uri === 'organizations') {
            $q->leftJoin('a.Organization o');
            $q->leftJoin('a.AdminRole r');
            $q->orderBy('org_display_name ASC');

            // flatten some org fields
            $q->addSelect('o.org_display_name as org_display_name');
            $this->extra_field_defs []= array('name' => 'org_display_name');
            $q->addSelect('o.org_uuid as org_uuid');
            $this->extra_field_defs []= array('name' => 'org_uuid');
        }
        elseif ($this->rel_uri === 'photo') {
            $q->addWhere('a.uuri_type = ?', 'P');
            $q->limit(1);
        }
        elseif ($this->rel_uri === 'activity') {
            $args = $this->paging_args;
            $offset = $args['start'] ? $args['start'] : 0;
            $limit = $args['limit'] ? $args['limit'] : 12;
            $data = $this->_get_recent_activity($limit, $offset);
            $this->crud_response($data);
        }
        elseif ($this->rel_uri === 'networks') {
            $q->addWhere('a.uuri_type = ?', 'N');
        }

        parent::_add_query_load_related($q, $deeply);
    }


    /**
     * Override to add custom update queries
     *
     * @param Doctrine_Record $record (reference) the record object to modify
     * @param associative-array $data   the radix data to update the record with
     */
    protected function _update_record(&$record, $data) {
        $conn = AIR2_DBManager::get_master_connection();

        if (!$this->base_uuid) {
            // create new user
            if (!isset($data['uem_address'])) {
                $this->crud_error('User email address required!');
            }
            else {
                $record->UserEmailAddress[0]->uem_address = $data['uem_address'];
                $record->UserEmailAddress[0]->uem_primary_flag = true;
                unset($data['uem_address']);
            }

            $org_uuid = isset($data['org_uuid']) ? $data['org_uuid'] : null;
            $ar_code = isset($data['ar_code']) ? $data['ar_code'] : 'R';
            unset($data['org_uuid']);
            unset($data['ar_code']);

            if ($org_uuid) {
                $org = Doctrine::getTable('Organization')->findOneBy('org_uuid', $org_uuid);
                if (!$org) $this->crud_error('Invalid Organization specified!');
                $ar = Doctrine::getTable('AdminRole')->findOneBy('ar_code', $ar_code);
                if (!$ar) $this->crud_error('Invalid AdminRole specified!');

                $record->UserOrg[0]->Organization = $org;
                $record->UserOrg[0]->AdminRole = $ar;
                $record->UserOrg[0]->uo_notify_flag = true;
                $record->UserOrg[0]->uo_home_flag = true;
            }
        }
        elseif ($this->rel_uri === 'photo') {
            $data['uuri_type'] = 'P';
            $data['uuri_handle'] = 'AIR2 Profile Photo';
        }
        elseif ($this->rel_uri === 'organizations') {
            $org_uuid = isset($data['org_uuid']) ? $data['org_uuid'] : null;
            unset($data['org_uuid']);

            if ($org_uuid) {
                $org = Doctrine::getTable('Organization')->findOneBy('org_uuid', $org_uuid);
                if (!$org) $this->crud_error('Invalid Organization specified!');
                $record->Organization = $org;
            }
        }
        elseif ($this->rel_uri === 'networks') {
            $data['uuri_type'] = 'N';
        }

        parent::_update_record($record, $data);
    }


    /**
     * Special hook to allow user to update their own org title
     *
     * @param string  $uuid
     * @param string  $rel_uri
     * @param string  $rel_uuid
     */
    public function crud_PUT_related($uuid, $rel_uri, $rel_uuid) {
        if ($rel_uri == 'organizations') {
            $data = $this->_decode_input();
            if (isset($data['uo_user_title'])) {
                // make sure they're not trying to set other stuff!
                $not_allowed = array('uo_org_id', 'uo_user_id', 'uo_ar_id');
                $both = array_intersect($not_allowed, array_keys($data));
                if (count($both) == 0) {
                    UserOrg::$ALLOW_OWNER_TITLE_CHANGE = true;
                }
            }
        }
        parent::crud_PUT_related($uuid, $rel_uri, $rel_uuid);
    }


    /**
     * Special case to allow Org MANAGER to add the User to their Org.
     *
     * @param string  $uuid
     * @param string  $rel_uri
     */
    public function crud_POST_related($uuid, $rel_uri) {
        if ($rel_uri == 'organizations') {
            User::$ALLOW_MANAGER_TO_WRITE = true;
        }
        parent::crud_POST_related($uuid, $rel_uri);
    }


    /**
     * Special case to allow Org MANAGER to create new Users.
     */
    public function crud_POST() {
        $post_data = $this->_decode_input();
        if (isset($post_data['org_uuid']) && isset($post_data['ar_code'])) {
            User::$ALLOW_MANAGER_TO_WRITE = true;
        }
        parent::crud_POST();
    }


    /**
     * Custom data and views for html requests
     *
     * @param associative-array $data
     * @param string  $view_name
     * @return string html body
     */
    public function get_html_body($data, $view_name=null) {
        if (!$this->base_uuid) { // redirect to directory
            redirect('directory');
        }
        elseif ($this->base_uuid && !$this->rel_uri) {
            $data = $this->_html_dashboard($data);
        }
        return parent::get_html_body($data, $view_name);
    }


    /**
     * Set the page title
     *
     * @param array   $head
     * @return array
     */
    public function get_html_head($head=array()) {
        if ($this->base_uuid) {
            $usr = $this->_find_base();
            $name = $usr->user_username;
            if ($usr->user_first_name && $usr->user_last_name) {
                $name = $usr->user_first_name.' '.$usr->user_last_name;
            }
            $head['title'] = AIR2_SYSTEM_DISP_NAME." - User: $name";
        }
        return $head;
    }


    /**
     * Get data for HTML dashboard
     *
     * @param associative-array $data
     * @return associative-array
     */
    protected function _html_dashboard($data) {
        // organizations
        $q = $this->build_query($this->base_uuid, 'organizations');
        $q->orderBy('uo_home_flag DESC');
        $q->limit(5);
        $org_data = $this->fetch_data($q, true, true);

        // photo (stored in user_uri)
        $q = $this->build_query($this->base_uuid, 'photo');
        $pic_data = $this->fetch_data($q, true, true);

        // email
        $q = $this->build_query($this->base_uuid, 'email');
        $uem_data = $this->fetch_data($q, true, true);

        // phone
        $q = $this->build_query($this->base_uuid, 'phone');
        $uph_data = $this->fetch_data($q, true, true);

        // admin roles
        $q = AIR2_Query::create()
        ->from('AdminRole ar')
        ->where("ar.ar_status = 'A'");
        $arl_data = $this->airquery->execute_query($q, array());

        // READ-ONLY activity list
        $act_data = $this->_get_recent_activity(12);

        // networks
        $q = $this->build_query($this->base_uuid, 'networks');
        $q->limit(6);
        $net_data = $this->fetch_data($q, true, true);

        return array(
            'user_uuid' => $this->base_uuid,
            'user_url'  => $this->uri_for('user').'/'.$this->base_uuid,
            'user_data' => $data,
            'org_data'  => $org_data,
            'pic_data'  => $pic_data,
            'uem_data'  => $uem_data,
            'uph_data'  => $uph_data,
            'arl_data'  => $arl_data,
            'act_data'  => $act_data,
            'net_data'  => $net_data,
        );
    }


    /**
     * Get recent generic "Activity" for a User
     *
     * @param int     $num    limit for the number to fetch
     * @param int     $offset
     * @return array metadata and radix for response
     */
    private function _get_recent_activity($num, $offset=0) {
        $user_id = $this->_find_base()->user_id;

        // get ID's in order
        $conn = AIR2_DBManager::get_connection();
        $sact = "select 'S' as type, sact_dtim as dtim, sact_id as id from ".
            "src_activity where sact_cre_user = $user_id";
        $pact = "select 'P' as type, pa_dtim as dtim, pa_id as id from ".
            "project_activity where pa_user_id = $user_id";
        $inqs = "select 'I' as type, inq_cre_dtim as dtim, inq_id as id from ".
            "inquiry where inq_cre_user = $user_id";
        $allq = "($sact) union ($pact) union ($inqs)";
        $all = $conn->fetchAll("$allq order by dtim desc limit $num offset $offset");

        // split into ID types
        $ids = array('S' => array(), 'P' => array(), 'I' => array());
        foreach ($all as $idx => $item) {
            $ids[$item['type']][] = $item['id'];
            unset($all[$idx]['id']);
        }

        // get source activity
        $q = AIR2_Query::create()->from('SrcActivity sa');
        $q->whereIn('sa.sact_id', $ids['S']);
        $q->leftJoin('sa.ActivityMaster m');
        $q->leftJoin('sa.Project p');
        $q->leftJoin('sa.Source s');
        $q->orderBy('sa.sact_dtim DESC');
        $sact_objs = count($ids['S']) ? $q->fetchArray() : array();
        foreach ($all as $idx => $item) {
            $all[$idx]['SrcActivity'] = ($item['type'] == 'S') ? array_shift($sact_objs) : null;
        }

        // get project activity
        $q = AIR2_Query::create()->from('ProjectActivity a');
        $q->whereIn('a.pa_id', $ids['P']);
        $q->leftJoin('a.ActivityMaster m');
        $q->leftJoin('a.Project p');
        $q->leftJoin('a.User u');
        ProjectActivity::joinRelated($q, 'a');
        $q->orderBy('a.pa_dtim DESC');
        $pact_objs = count($ids['P']) ? $q->fetchArray() : array();
        foreach ($all as $idx => $item) {
            $all[$idx]['ProjectActivity'] = ($item['type'] == 'P') ? array_shift($pact_objs) : null;
        }

        // get inquiries sent
        $q = AIR2_Query::create()->from('Inquiry i');
        $q->whereIn('i.inq_id', $ids['I']);
        $q->orderBy('i.inq_cre_dtim DESC');
        $inq_objs = count($ids['I']) ? $q->fetchArray() : array();
        foreach ($all as $idx => $item) {
            $all[$idx]['Inquiry'] = ($item['type'] == 'I') ? array_shift($inq_objs) : null;
        }

        // get total
        $total = $conn->fetchOne("select count(*) from ($allq) a", array(), 0);

        // return formatted data
        $flds = array(
            array('name' => 'type'),
            array('name' => 'dtim'),
            array('name' => 'SrcActivity'),
            array('name' => 'ProjectActivity'),
            array('name' => 'Inquiry'),
        );
        $this->airquery->process_radix($all);
        $data = array(
            'total' => $total,
            'radix' => $all,
            'metaData' => $this->_create_metadata_basic('dtim', $flds),
        );
        return $data;
    }


    /**
     * Provide image proxying for the User Photo
     *
     * @param string  $uuid    identifier of base model
     * @param string  $rel_uri uri of related model
     * @return radix (list) and metaData
     */
    public function crud_GET_list_related($uuid, $rel_uri) {
        if ($rel_uri != 'photo')
            return parent::crud_GET_list_related ($uuid, $rel_uri);

        // fetch and proxy the "photo"
        $q = $this->build_query($uuid, 'photo');
        $user_uuri = $q->fetchOne();
        $photo = ($user_uuri) ? $user_uuri->uuri_value : null;
        air2_proxy_image($photo, $this->uri_for('css/img/not_found.jpg'));
    }


    /**
     * GET parameter 'type' to limit user_types.
     *
     * @param AIR2_Query $q    query to alter
     * @param string  $type user_type to include in search
     */
    public function query_user_type($q, $type) {
        $q->addWhere("a.user_type = ?", $type);
    }


    /**
     * GET parameter 'excl_org' to show all users not in an organization.
     *
     * @param AIR2_Query $q
     * @param string  $org_uuid
     */
    public function query_excl_org($q, $org_uuid) {
        $orgq = "SELECT zo.org_id FROM Organization zo WHERE zo.org_uuid = ?";
        $excl = "SELECT zuo.uo_user_id FROM UserOrg zuo WHERE zuo.uo_org_id = ($orgq)";
        $q->addWhere("a.user_id NOT IN ($excl)", $org_uuid);
    }


}
